#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "Log.hpp"
#include "InetAddr.hpp"

enum
{
    USE_ERR,
    SOCKET_ERR,
    BIND_ERR,
};

static const int defaultFd = -1;

class UdpServer
{
public:
    UdpServer(uint16_t port)
        : _port(port), _sockfd(defaultFd)
    {
    }
    void InitServer()
    {
        _sockfd = ::socket(AF_INET, SOCK_DGRAM, 0);
        if (_sockfd < 0)
        {
            LOG(FATAL, "socket create error\n");
            exit(SOCKET_ERR);
        }
        LOG(INFO, "socket create success!\n");

        struct sockaddr_in local;
        memset(&local, 0, sizeof local);
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = INADDR_ANY;

        int n = ::bind(_sockfd, reinterpret_cast<struct sockaddr *>(&local), sizeof local);
        if (n < 0)
        {
            LOG(FATAL, "socket bind error\n");
            exit(BIND_ERR);
        }
        LOG(INFO, "bind sueecess!\n");
    }
    void Start()
    {
        while (true)
        {
            struct sockaddr_in client;
            socklen_t len = sizeof client;
            // 1. 获取数据
            char buff[1024];
            ssize_t num = recvfrom(_sockfd, buff, sizeof(buff) - 1, 0, reinterpret_cast<struct sockaddr *>(&client), &len);
            if (num > 0)
            {
                InetAddr addr(client);
                // 2. 处理数据
                buff[num] = 0;
                LOG(INFO, "client[%s:%d] say# %s\n", addr.IP().c_str(), addr.Port(), buff);
                // 3. 发送数据
                num = sendto(_sockfd, buff, strlen(buff), 0, reinterpret_cast<struct sockaddr *>(&client), sizeof client);
                if (num < 0)
                {
                    LOG(INFO, "send error\n");
                    break;
                }
            }
            else
            {
                // == 0 client quie
                // < 0  recv error
                LOG(INFO, "quit......\n");
                break;
            }
        }
    }
    ~UdpServer()
    {
    }

private:
    int _sockfd;
    uint16_t _port;
};